﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

using BEGDC.Office.Interface;

namespace BEGDC.Office.Library
{
    public class OfficeSessionType
    {
        public const string Excel = "Excel";
        public const string Word = "Word";
        public const string PowerPoint = "PowerPoint";
    }

    public abstract class SessionFactory
    {
        private Queue<SessionSingle> tasks;

        private SessionSingle current_task;

        private const int Time_Out = 90000;
        protected virtual int Timeout
        {
            get
            {
                return Time_Out;
            }
        }

        private const int Queue_Size = 25;
        protected virtual int QueueSize
        {
            get
            {
                return Queue_Size; 
            }
        }

        protected SessionFactory()
        {
            tasks = new Queue<SessionSingle>(QueueSize);
            current_task = null;
        }

        protected OfficeSession OpenSession()
        {
            SessionSingle single = new SessionSingle();

            lock (this)
            {
                if ((current_task == null) && (tasks.Count == 0))
                {
                    single.Single.Set();
                }
                else
                {
                    tasks.Enqueue(single);
                }
            }
            if (!single.Single.WaitOne(Timeout, true))
            {
                single.IsTimeout = true;
                return null;
            }

            OfficeSession session = CreateSessionObject();
            session.OnClosed += new EventHandler(CloseSession);
            return session;
        }

        private void CloseSession(object sender, EventArgs args)
        {
            lock (this)
            {
                while (tasks.Count != 0)
                {
                    SessionSingle single = tasks.Dequeue();
                    current_task = single;
                    if (single.IsTimeout)
                    {
                        continue;
                    }
                    single.Single.Set();
                    break;
                }
                current_task = null;
            }
        }

        protected abstract OfficeSession CreateSessionObject();

        private class SessionSingle
        {
            internal ManualResetEvent Single;

            internal bool IsTimeout;

            internal SessionSingle()
            {
                Single = new ManualResetEvent(false);
                IsTimeout = false;
            }
        }

        private static ExcelSessionFactory excel_factory = new ExcelSessionFactory();

        public static OfficeSession OpenSession(string sessionType)
        {
            if (sessionType == OfficeSessionType.Excel)
            {
                return excel_factory.OpenSession();
            }
            return null;
        }
    }

    
}
